﻿/*
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * See product pages for more information.
 * http://closesudoku.codeplex.com
 * Copyright (C), 2011, hrondra
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;

using Close.Data;
using Close.Properties;

namespace Close.Classes
{
    /// <summary>
    /// Working with imported values.
    /// </summary>
    class PuzzleImporter
    {

        /// <summary>
        /// Import values from external file (adding to internal).
        /// </summary>
        /// <param name="filePath">file path</param>
        /// <remarks>Do not forget to update datasource.</remarks>
        public void Import(string filePath)
        {
            //Load previously imported values from internal file
            GameData previouslyImported = LoadImportedPuzzlesValues();

            //Add new values.
            LoadXml(filePath, ref previouslyImported);

            //Save the values in to the native file file.
            SaveImportedValues(previouslyImported);
        }

        /// <summary>
        /// Load sudoku from opensudoku format - add them to dataset with imported.
        /// </summary>
        /// <param name="filePath">file path</param>
        /// <param name="imported">existing values in application</param>
        private void LoadXml(string filePath, ref GameData imported)
        {
            /*
               <opensudoku>
               <name>
               <game data="379000014060010070080009005435007000090040020000800436900700080040080050850000249" />
            */
            string name = String.Empty;
            byte freeLevel = imported.GetMaxGameLevel();
            freeLevel++;
            ushort freegameId = (ushort)(imported.GetMaxGameId() + 1);
            bool supportedXmlFormat = false;

            XmlTextReader reader = new XmlTextReader(filePath);
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        if (reader.IsStartElement())
                        {
                            if (reader.Name.ToLower() == "opensudoku")
                                supportedXmlFormat = true;
                            else
                            {
                                if (!supportedXmlFormat)
                                    throw new Exception(Resources.ImportRootMissing);
                                if (reader.Name.ToLower() == "name")
                                {
                                    Close.Data.GameData.LevelRow newLevelRow = imported.Level.NewLevelRow();
                                    newLevelRow.lid = freeLevel;
                                    reader.Read();
                                    newLevelRow.title = name = reader.Value;
                                    imported.Level.Rows.Add(newLevelRow);
                                    freeLevel++;
                                }
                                if (reader.Name.ToLower() == "game")
                                {
                                    if (String.IsNullOrEmpty(name))
                                        throw new Exception(Resources.ImportLevelMissing);

                                    while (reader.MoveToNextAttribute())
                                    {
                                        if (reader.Name.ToLower() == "data")
                                        {
                                            Close.Data.GameData.ImprintedRow newGameRow = imported.Imprinted.NewImprintedRow();
                                            newGameRow.gid = freegameId;
                                            newGameRow.values = reader.Value;
                                            newGameRow.lid = (byte)(freeLevel - 1);
                                            imported.Imprinted.Rows.Add(newGameRow);
                                            freegameId++;
                                        }
                                    }
                                }
                            }
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// Add imported levels (folders with names).
        /// </summary>
        /// <param name="current">current dataset</param>
        public void AddAllGameLevelesFromImported(ref GameData current)
        {
            GameData newData = LoadImportedPuzzlesValues();
            current.Level.Merge(newData.Level);
        }

        /// <summary>
        /// Add imported puzzles.
        /// </summary>
        /// <param name="current">current dataset</param>
        public void AddValuesFromImported(ref GameData current, int level)
        {
            GameData newData = LoadImportedPuzzlesValues();

            foreach (Data.GameData.ImprintedRow item in newData.Imprinted.Select("lid = " + level.ToString()))
            {
                current.Imprinted.ImportRow(item);
            }
        }

        /// <summary>
        /// Get all imported games.
        /// </summary>
        public GameData GetAllValuesFromImported()
        {
            return LoadImportedPuzzlesValues();
        }

        /// <summary>
        /// File path to internally imported games.
        /// </summary>
        public string ImportedPuzzlesFile
        {
            get
            {
                String full_path = System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase;
                String directory_path = full_path.Substring(0, full_path.LastIndexOf("\\"));
                if (!Directory.Exists(directory_path))
                {
                    //should exist because of configuration file, but for sure
                    Directory.CreateDirectory(directory_path);
                }
                return Path.Combine(directory_path, "Settings\\puzzles.bin");
            }
        }

        /// <summary>
        /// Load imported puzzles from internal file.
        /// </summary>
        /// <returns></returns>
        private GameData LoadImportedPuzzlesValues()
        {
            String pth = ImportedPuzzlesFile;
            GameData loadedValues = new GameData();

            if (File.Exists(pth))
                loadedValues.ReadXml(pth);
            return loadedValues;
        }

        /// <summary>
        /// Save dataset to native file.
        /// </summary>
        /// <param name="importedValues">all (in fact only imported) values to save</param>
        private void SaveImportedValues(GameData importedValues)
        {
            importedValues.WriteXml(ImportedPuzzlesFile);
        }

        /// <summary>
        /// Rename level - load data, rename, save data.
        /// </summary>
        public void RenameLevel(byte lid, string newName)
        {
            GameData completeData = LoadImportedPuzzlesValues();
            completeData.Level.FindBylid(lid).title = newName;
            SaveImportedValues(completeData);
        }

        /// <summary>
        /// Delete level (with all puzzles) from imported games and playing games.
        /// </summary>
        /// <param name="lid">level id</param>
        public void DeleteLevelFolder(byte lid)
        {
            //Delete from imported.
            GameData completeData = LoadImportedPuzzlesValues();
            //Delete imprinted values.
            List<ushort> gidList = completeData.Imprinted.DeleteRows(lid);
            completeData.Level.FindBylid(lid).Delete();
            SaveImportedValues(completeData);
            //Saved games are in different file - so it is necessary delete them too.
            GameDatabase.DeleteAllAboutGameFolder(gidList);
        }
    }
}
